home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 1 / Mac Magazin and MacEasy Magazine CD - Issue 01.iso / Sharewarebibliothek / Powermac / C64 / SOURCE / Floppy.c < prev    next >
Text File  |  1994-06-06  |  32KB  |  1,608 lines

  1. /*
  2.     Commodore 64 Emulator v0.4      Earle F. Philhower III 
  3.     Copyright (C) 1993-4            (st916w9r@dunx1.ocs.drexel.edu)
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. This file stolen from x64 0.2.1.  Most bugs in the file are of my own making.
  20. I've removed the 64 byte header so it'll run *.D64 images w/o conversion.
  21. Also, most of the ANSI calls have been xlated into native Mac FS calls or my
  22. own memory management routines.
  23.  
  24. The buffer allocations are no longer done w/malloc, but instead used buffers
  25. that are allocated only once.  This is necessary to avoid heap fragmentation
  26. on the non memory-mapping MacOS.
  27.  
  28.  * 1541.c -- 1541 Floppy Drive emulation. Emulator emulates 1541 reasonably
  29.  *         well as long as 1541 is used through ROM-interface (no
  30.  *         turboloaders supported). Also REL-file type is still missing.
  31.  *
  32.  * $Id: 1541.c,v 1.4 1993/11/10 01:55:34 jopi Exp $
  33.  *
  34.  * This file is part of Commodore 64 emulator.
  35.  * See README for copyright notice
  36.  *
  37.  *
  38.  * Written by
  39.  *   Teemu Rantanen (tvr@cs.hut.fi)
  40.  *
  41.  * .... yadda yadda yadda ....
  42.  *
  43.  */
  44.  
  45.  
  46. #include <stdio.h>
  47. #include <string.h>
  48.  
  49. #include "Processor.h"
  50. #include "Resources.h"
  51. #include "Serial.h"
  52. #include "Floppy.h"
  53. #include "FileTypes.h"
  54. #include "Error.h"
  55.  
  56. typedef struct bufferinfo_s {
  57.     int     mode;    /* mode on this buffer */
  58.     int     readmode;    /* is this for reading or writing */
  59.     int     secondary;    /* this is not needed */
  60.     byte   *buffer;    /* use this to save data */
  61.     byte   *slot;    /* save data for directory-slot */
  62.     int     bufptr;    /* use this to save/read data to disk */
  63.     int     length;    /* directory-read length */
  64. }       bufferinfo_t;
  65.  
  66. typedef long off_t;
  67.  
  68. extern Cursor commieCursor, diskCursor;
  69. extern int programMode;
  70.  
  71. byte normBuffer[16][256];
  72. byte normSlot[16][32];
  73. byte dirBuffer[8192];
  74. static int floppyInDrive=0;
  75.  
  76.  
  77. #define BUFFER_NOT_IN_USE        0
  78. #define BUFFER_DIRECTORY_READ        1
  79. #define BUFFER_SEQUENTIAL        2
  80. #define BUFFER_MEMORY_BUFFER        3
  81. #define BUFFER_OTHER            4
  82. #define BUFFER_COMMAND_CHANNEL        5
  83.  
  84.  
  85. #define WRITE_BLOCK             512
  86.  
  87.  
  88. /*
  89.  * Actually, serial-code errors ...
  90.  */
  91.  
  92. #define SLOT_TYPE_OFFSET        2
  93. #define SLOT_FIRST_TRACK        3
  94. #define SLOT_FIRST_SECTOR        4
  95. #define SLOT_NAME_OFFSET        5
  96. #define SLOT_NR_BLOCKS            30
  97.  
  98. #define BAM_FIRST_TRACK            0
  99. #define BAM_FIRST_SECTOR        1
  100. #define BAM_FORMAT_TYPE            2
  101. #define BAM_BIT_MAP            4
  102. #define BAM_DISK_NAME            144
  103. #define BAM_DISK_ID            162
  104. #define BAM_VERSION            165
  105.  
  106.  
  107. #define BAM_SET(n)    (bamp[1+(n)/8] |= (1 << ((n) % 8)))
  108. #define BAM_CLR(n)    (bamp[1+(n)/8] &= ~(1 << ((n) % 8)))
  109. #define BAM_ISSET(n)  (bamp[1+(n)/8] & (1 << ((n) % 8)))
  110.  
  111.  
  112. static byte bam[256];
  113.  
  114. static int sector_map[36] =
  115. {
  116.     0,
  117.     21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
  118.     19, 19, 19, 19, 19, 19, 19,
  119.     18, 18, 18, 18, 18, 18,
  120.     17, 17, 17, 17, 17
  121. };
  122.  
  123.  
  124. static char *slot_type[] =
  125. {
  126.     "   ", "SEQ", "PRG", "USR", "REL", "   ", "   ", "   "
  127. };
  128.  
  129. static bufferinfo_t floppy_buffers[16];
  130.  
  131. static int floppy_find_slot;
  132. static byte floppy_find_buffer[256];
  133. static int floppy_find_current_track;
  134. static int floppy_find_current_sector;
  135.  
  136. short     FloppyActiveFd = -1;
  137.  
  138. static char *floppy_find_name;
  139. static int floppy_find_length;
  140. static int floppy_find_type;
  141.  
  142.  
  143. int FloppyInitialize ( void );
  144. byte Open1541 ( char *name, int length, int secondary );
  145. byte Close1541 ( int secondary );
  146. byte Read1541 ( unsigned char *data, int secondary );
  147. byte Write1541 ( unsigned char data, int secondary );
  148. void Flush1541 ( int secondary );
  149. static int floppy_parse_name ( char *name, int length, char *realname, int *reallength, int *readmode, int *filetype );
  150. static int floppy_create_directory ( char *name, int length, int filetype, int secondary, unsigned char *outputptr );
  151. static void set_find_first_slot ( char *name, int length, int type );
  152. static unsigned char *find_next_slot ( void );
  153. static void no_a0_pads ( unsigned char *ptr, int l );
  154. static int floppy_read_block ( unsigned char *buf, int track, int sector );
  155. static int floppy_write_block ( unsigned char *buf, int track, int sector );
  156. static void floppy_error ( int code, int track, int sector );
  157. static void remove_slot ( unsigned char *slot );
  158. static int write_sequential_buffer ( unsigned char *slot, unsigned char *buf, int length );
  159. static int alloc_free_sector ( int *track, int *sector );
  160. static int allocate_sector ( int track, int sector );
  161. static off_t offset_from_track_and_sector ( int track, int sector );
  162. static int free_sector ( int track, int sector );
  163. static int floppy_name_match ( unsigned char *slot, char *name, int length, int type );
  164. static void floppy_close_all_channels ( void );
  165. static int do_initialize ( void );
  166. static int do_validate ( void );
  167. static int do_format ( char *name, unsigned char *id, unsigned char *minus );
  168. static int do_command_channel_write ( unsigned char *buf, int length );
  169. static int do_block_command ( char command, char *buffer );
  170. extern void attach_floppy_image ( char *name );
  171. static int mystrncpy ( unsigned char *d, unsigned char *s, int n );
  172. extern int write_fs ( unsigned char data, int secondary );
  173. extern int petconv ( int c );
  174. extern void petconvstring ( char *c );
  175. extern int read_fs ( unsigned char *data, int secondary );
  176. extern int open_fs ( char *name, int length, int secondary );
  177. extern int close_fs ( int secondary );
  178.  
  179. int FloppyInitialize(void)
  180. {
  181.     int i;
  182.     
  183.     for (i=0; i<15; i++) floppy_buffers[i].mode=BUFFER_NOT_IN_USE;
  184.  
  185.     floppy_buffers[15].mode=BUFFER_COMMAND_CHANNEL;
  186.     floppy_buffers[15].buffer=normBuffer[15];
  187.     
  188.     AddSerialDevice(8, Read1541, Write1541, Open1541, Close1541, Flush1541);
  189.  
  190.     floppy_error(73, 0, 0);
  191.     
  192.     return kNoError;
  193. }
  194.  
  195. byte Open1541(char *name, int length, int secondary)
  196. {
  197.     bufferinfo_t *p = &floppy_buffers[secondary];
  198.     char    realname[256];
  199.     int     reallength;
  200.     int     readmode;
  201.     int     filetype;
  202.  
  203.     byte *slot;
  204.     int     i;
  205.  
  206.     /*
  207.      * No floppy in drive ?
  208.      */
  209.     if (FloppyActiveFd < 0)
  210.     return kFloppyError;
  211.  
  212.     /*
  213.      * Clear error flag
  214.      */
  215.     floppy_error(0, 0, 0);
  216.  
  217.     /*
  218.      * If channel is command channel, name will be used as write. Return only
  219.      * status of last write ...
  220.      */
  221.     if (p -> mode == BUFFER_COMMAND_CHANNEL) {
  222.     int     i;
  223.     int     status = kSerialOK;
  224.     for (i = 0; i < length; i++)
  225.         status = Write1541(name[i], secondary);
  226.     return status;
  227.     }
  228.     /*
  229.      * In use ?
  230.      */
  231.     if (p -> mode != BUFFER_NOT_IN_USE) {
  232.     floppy_error(70, 0, 0);
  233.     return kFloppyError;
  234.     }
  235.     /*
  236.      * Filemode / type
  237.      */
  238.     if (secondary == 1)
  239.     readmode = 0;
  240.     else
  241.     readmode = 1;
  242.  
  243.     filetype = 0;
  244.  
  245.     i = floppy_parse_name(name, length, realname, &reallength,
  246.     &readmode, &filetype);
  247.  
  248.     if (i != kSerialOK)
  249.     return i;
  250.  
  251.     /*
  252.      * Internal buffer ?
  253.      */
  254.     if (*name == '#') {
  255.     p -> mode = BUFFER_MEMORY_BUFFER;
  256.     p -> buffer = normBuffer[secondary];
  257.     p -> bufptr = 0;
  258.     return kSerialOK;
  259.     }
  260.     /*
  261.      * Directory read
  262.      */
  263.     if (*name == '$') {
  264.     if (!readmode)
  265.         return kFloppyError;
  266.  
  267.     p -> mode = BUFFER_DIRECTORY_READ;
  268.     p -> buffer = dirBuffer;
  269.  
  270.     /*
  271.      * fix this someday
  272.      */
  273.     if (*realname != '$')
  274.         p -> length = floppy_create_directory(realname, reallength, filetype,
  275.         secondary, p -> buffer);
  276.     else
  277.         p -> length = floppy_create_directory("*", 1, 0, secondary,
  278.         p -> buffer);
  279.     p -> bufptr = 0;
  280.  
  281.     return kSerialOK;
  282.     }
  283.     /*
  284.      * now, set filetype according secondary address, if it was not specified
  285.      * on filename
  286.      */
  287.     if (!filetype)
  288.     filetype = secondary < 2 ? 2 : 1;
  289.  
  290.     /*
  291.      * Check that there is room on directory.
  292.      */
  293.     set_find_first_slot(name, length, 0);
  294.     slot = find_next_slot();
  295.  
  296.     p -> readmode = readmode;
  297.  
  298.     /*
  299.      * Open file for reading
  300.      */
  301.     if (readmode) {
  302.     int     type;
  303.     int     status;
  304.  
  305.     if (!slot) {
  306.         Close1541(secondary);
  307.         floppy_error(62, 0, 0);
  308.         return kFloppyError;
  309.     }
  310.     type = slot[SLOT_TYPE_OFFSET] & 0x07;
  311.  
  312.     if (type != filetype) {
  313.         floppy_error(64, 0, 0);
  314.         return kFloppyError;
  315.     }
  316.     /*
  317.      * Seq, Prg
  318.      */
  319.     if (type == 1 || type == 2) {
  320.         p -> mode = BUFFER_SEQUENTIAL;
  321.         p -> bufptr = 2;
  322.         p -> buffer = normBuffer[secondary];
  323.  
  324.         status = floppy_read_block(p -> buffer, (int) slot[SLOT_FIRST_TRACK],
  325.         (int) slot[SLOT_FIRST_SECTOR]);
  326.  
  327.         if (status < 0) {
  328.         Close1541(secondary);
  329.         return kFloppyError;
  330.         }
  331.         return kSerialOK;
  332.     }
  333.     /*
  334.      * Unsupported filetype
  335.      */
  336.     return kFloppyError;
  337.     }
  338.     /*
  339.      * Write
  340.      */
  341.     if (slot) {
  342.     if (*name == '@')
  343.         remove_slot(slot);
  344.     else {
  345.         Close1541(secondary);
  346.         floppy_error(63, 0, 0);
  347.         return kFloppyError;
  348.     }
  349.     }
  350.     /*
  351.      * Create slot information. (XXXX: should write directoryentry to disk ?)
  352.      */
  353.     p -> slot = normSlot[secondary];
  354.     memset(p -> slot, 0, 32);
  355.     memset(p -> slot + SLOT_NAME_OFFSET, 0xa0, 16);
  356.     memcpy(p -> slot + SLOT_NAME_OFFSET, realname, reallength);
  357.  
  358.     p -> slot[SLOT_TYPE_OFFSET] = filetype;
  359.  
  360.     p -> buffer = normBuffer[secondary];
  361.     p -> mode = BUFFER_SEQUENTIAL;
  362.     p -> bufptr = 2;
  363.  
  364.     return kSerialOK;
  365. }
  366.  
  367.  
  368. byte Close1541(int secondary)
  369. {
  370.     byte   *e;
  371.     bufferinfo_t *p = &floppy_buffers[secondary];
  372.  
  373.     switch (p -> mode) {
  374.       case BUFFER_NOT_IN_USE:
  375.     return kFloppyError;
  376.  
  377.       case BUFFER_MEMORY_BUFFER:
  378.       case BUFFER_DIRECTORY_READ:
  379.     p -> mode = BUFFER_NOT_IN_USE;
  380.     p -> buffer = NULL;
  381.     break;
  382.  
  383.       case BUFFER_SEQUENTIAL:
  384.     if (!p -> readmode) {
  385.         /*
  386.          * Flush bytes and write slot to directory
  387.          */
  388.         write_sequential_buffer(p -> slot, p -> buffer, p -> bufptr);
  389.         set_find_first_slot(NULL, -1, 0);
  390.  
  391.         e = find_next_slot();
  392.  
  393.         if (!e) {
  394.         p -> mode = BUFFER_NOT_IN_USE;
  395.         p -> buffer = NULL;
  396.  
  397.         floppy_error(72, 0, 0);
  398.         return kFloppyError;
  399.         }
  400.         p -> slot[SLOT_TYPE_OFFSET] |= 0x80;
  401.         memcpy(&floppy_find_buffer[floppy_find_slot * 32 + 2], p -> slot + 2,
  402.         30);
  403.  
  404.         floppy_write_block(floppy_find_buffer,
  405.         floppy_find_current_track,
  406.         floppy_find_current_sector);
  407.         floppy_write_block(bam, 18, 0);
  408.     }
  409.     p -> mode = BUFFER_NOT_IN_USE;
  410.     p -> buffer = NULL;
  411.     break;
  412.  
  413.       case BUFFER_COMMAND_CHANNEL:
  414.     floppy_close_all_channels();
  415.     break;
  416.  
  417.       default:
  418.       InternalError(0);
  419.     }
  420.  
  421.     return kSerialOK;
  422. }
  423.  
  424.  
  425. byte Read1541(unsigned char *data, int secondary)
  426. {
  427.     bufferinfo_t *p = &floppy_buffers[secondary];
  428.  
  429.     switch (p -> mode) {
  430.       case BUFFER_NOT_IN_USE:
  431.     floppy_error(61, 0, 0);
  432.     return kFloppyError;
  433.  
  434.       case BUFFER_DIRECTORY_READ:
  435.     if (p -> bufptr >= p -> length)
  436.         return kSerialEOF;
  437.     *data = p -> buffer[p -> bufptr];
  438.     p -> bufptr++;
  439.     break;
  440.  
  441.       case BUFFER_MEMORY_BUFFER:
  442.     if (p -> bufptr >= 256)
  443.         return kSerialEOF;
  444.     *data = p -> buffer[p -> bufptr];
  445.     p -> bufptr++;
  446.     break;
  447.  
  448.       case BUFFER_SEQUENTIAL:
  449.     if (!p -> readmode)
  450.         return kFloppyError;
  451.  
  452.     /*
  453.      * Read next block if needed
  454.      */
  455.     if (p -> buffer[0]) {
  456.         if (p -> bufptr >= 256) {
  457.         floppy_read_block(p -> buffer,
  458.             (int) p -> buffer[0],
  459.             (int) p -> buffer[1]);
  460.         p -> bufptr = 2;
  461.         }
  462.     } else {
  463.         if (p -> bufptr > p -> buffer[1])
  464.         return kSerialEOF;
  465.     }
  466.  
  467.     *data = p -> buffer[p -> bufptr];
  468.     p -> bufptr++;
  469.     break;
  470.  
  471.       case BUFFER_COMMAND_CHANNEL:
  472.     if (p -> bufptr > p -> length) {
  473.         floppy_error(0, 0, 0);
  474.         return kSerialEOF;
  475.     }
  476.     *data = p -> buffer[p -> bufptr];
  477.     p -> bufptr++;
  478.     break;
  479.  
  480.       default:
  481.         InternalError(0);
  482.     }
  483.  
  484.     return kSerialOK;
  485. }
  486.  
  487.  
  488. byte Write1541(unsigned char data, int secondary)
  489. {
  490.     int     total = 0;
  491.     int     e;
  492.     bufferinfo_t *p = &floppy_buffers[secondary];
  493.  
  494.     switch (p -> mode) {
  495.       case BUFFER_NOT_IN_USE:
  496.     floppy_error(61, 0, 0);
  497.     return kFloppyError;
  498.  
  499.       case BUFFER_DIRECTORY_READ:
  500.     floppy_error(60, 0, 0);
  501.     return kFloppyError;
  502.  
  503.       case BUFFER_MEMORY_BUFFER:
  504.     if (p -> bufptr >= 256)
  505.         return kFloppyError;
  506.     p -> buffer[p -> bufptr] = data;
  507.     p -> bufptr++;
  508.     return kSerialOK;
  509.  
  510.       case BUFFER_SEQUENTIAL:
  511.     if (p -> readmode)
  512.         return kFloppyError;
  513.  
  514.     if (p -> bufptr >= 256) {
  515.         p -> bufptr = 2;
  516.         e = write_sequential_buffer(p -> slot, p -> buffer, WRITE_BLOCK);
  517.         if (e < 0)
  518.         return kFloppyError;
  519.     }
  520.     p -> buffer[p -> bufptr] = data;
  521.     p -> bufptr++;
  522.     break;
  523.  
  524.       case BUFFER_COMMAND_CHANNEL:
  525.     if (p -> bufptr >= 256)
  526.         return kFloppyError;
  527.     p -> buffer[p -> bufptr] = data;
  528.     p -> bufptr++;
  529.     break;
  530.  
  531.       default:
  532.         InternalError(0);
  533.     }
  534.  
  535.     return total;
  536. }
  537.  
  538.  
  539. void Flush1541(int secondary)
  540. {
  541.     bufferinfo_t *p = &floppy_buffers[secondary];
  542.  
  543.     if (p -> mode != BUFFER_COMMAND_CHANNEL)
  544.     return;
  545.  
  546.     do_command_channel_write(p -> buffer, p -> bufptr);
  547.     p -> bufptr = 0;
  548.     floppy_error(0, 0, 0);
  549. }
  550.  
  551.  
  552.  
  553. /*
  554.  * Parse name realname, type and read/write mode. '@' on write must
  555.  * be checked elsewhere
  556.  */
  557. static int floppy_parse_name(char *name, int length, char *realname, int *reallength, int *readmode, int *filetype)
  558. {
  559.     char   *p;
  560.     char   *c;
  561.     int     t;
  562.  
  563.     p = (char *)memchr(name, ':', length);
  564.     if (p)
  565.     p++;
  566.     else
  567.     p = name;
  568.  
  569.     if (*name == '@' && p == name)
  570.     p++;
  571.  
  572.     t = length - (p - name);
  573.     *reallength = 0;
  574.     c = realname;
  575.  
  576.     while (t > 0 && *p != ',') {
  577.     t--;
  578.     (*reallength)++;
  579.     *c++ = *p++;
  580.     }
  581.  
  582.     /*
  583.      * Change modes ?
  584.      */
  585.     while (t > 0) {
  586.     t--;
  587.     p++;
  588.  
  589.     if (t == 0) {
  590.         return kFloppyError;
  591.     }
  592.     if (*p == 'R')
  593.         *readmode = 1;
  594.     else if (*p == 'W')
  595.         *readmode = 0;
  596.     else if (*p == 'S')
  597.         *filetype = 1;
  598.     else if (*p == 'P')
  599.         *filetype = 2;
  600.     else if (*p == 'U')
  601.         *filetype = 3;
  602.     else if (*p == 'R')
  603.         *filetype = 4;
  604.     else
  605.         return kFloppyError;
  606.  
  607.     c = (char *)memchr(p, ',', t);
  608.  
  609.     if (c) {
  610.         t -= (c - p);
  611.         p = c;
  612.     } else
  613.         t = 0;
  614.     }
  615.  
  616.     return kSerialOK;
  617. }
  618.  
  619.  
  620. #define SET_LO_HI(p, val) {*(p)++ = (val) & 0xff; *(p)++ = ((val)/256) & 0xff;}
  621.  
  622. /*
  623.  * Create directory listing.
  624.  * If filetype is 0, match for all
  625.  */
  626. static int floppy_create_directory(char *name, int length, int filetype, int secondary, unsigned char *outputptr)
  627. {
  628.     byte   *l;
  629.     byte *p;
  630.     byte   *tmpsl;
  631.     byte   *origptr = outputptr;
  632.     int     t;
  633.     int     bf;
  634.  
  635.     int     addr;
  636.  
  637.  
  638.     set_find_first_slot(name, length, filetype);
  639.  
  640.     l = outputptr;
  641.  
  642.     /*
  643.      * Start-address
  644.      */
  645.     addr = 0x401;
  646.     SET_LO_HI(l, addr);
  647.  
  648.     /*
  649.      * Set next line offset later
  650.      */
  651.     l += 2;
  652.  
  653.     /*
  654.      * Line number 0
  655.      */
  656.     SET_LO_HI(l, 0);
  657.  
  658.     /*
  659.      * Reverse on
  660.      */
  661.     *l++ = (char) 0x12;
  662.  
  663.     *l++ = '\"';
  664.     memcpy(l, &bam[BAM_DISK_NAME], 16);
  665.     no_a0_pads(l, 16);
  666.     l += 16;
  667.     *l++ = '\"';
  668.     *l++ = ' ';
  669.     memcpy(l, &bam[BAM_DISK_ID], 5);
  670.     no_a0_pads(l, 5);
  671.     l += 5;
  672.  
  673.     *l++ = 0;
  674.  
  675.     /*
  676.      * Address of next line
  677.      */
  678.     addr += ((l - outputptr) - 2);
  679.  
  680.     outputptr[2] = addr & 0xff;
  681.     outputptr[3] = (addr / 256) & 0xff;
  682.  
  683.     outputptr = l;
  684.  
  685.     /*
  686.      * Now, list files
  687.      */
  688.     while ((p = find_next_slot())) {
  689.     if (p[SLOT_TYPE_OFFSET]) {
  690.  
  691.         l += 2;
  692.  
  693.         /*
  694.          * Length and spaces
  695.          */
  696.         t = p[SLOT_NR_BLOCKS] + p[SLOT_NR_BLOCKS + 1] * 256;
  697.  
  698.         SET_LO_HI(l, t);
  699.  
  700.         if (t < 10)
  701.         *l++ = ' ';
  702.         if (t < 100)
  703.         *l++ = ' ';
  704.  
  705.         /*
  706.          * name
  707.          */
  708.         *l++ = ' ';
  709.         *l++ = '\"';
  710.         memcpy(l, &p[SLOT_NAME_OFFSET], 16);
  711.  
  712.         for (t = 0; (t < 16) && (p[SLOT_NAME_OFFSET + t] != 0xa0);)
  713.         t++;
  714.  
  715.         no_a0_pads(l, 16);
  716.  
  717.         l[16] = ' ';
  718.         l[t] = '\"';
  719.         l += 17;
  720.  
  721.         /*
  722.          * type
  723.          */
  724.         *l++ = p[SLOT_TYPE_OFFSET] & 0x80 ? ' ' : '*';
  725.  
  726.         tmpsl = (byte *)slot_type[p[SLOT_TYPE_OFFSET] & 0x07];
  727.  
  728.         memcpy(l, tmpsl, 3);
  729.         l += 3;
  730.  
  731.         /*
  732.          * End
  733.          */
  734.         *l++ = ' ';
  735.         *l++ = ' ';
  736.         *l++ = (char) 0;
  737.  
  738.         /*
  739.          * New address
  740.          */
  741.         addr += l - outputptr;
  742.  
  743.         outputptr[0] = addr & 0xff;
  744.         outputptr[1] = (addr / 256) & 0xff;
  745.  
  746.         outputptr = l;
  747.     }
  748.     }
  749.  
  750.     /*
  751.      * calculate blocks free
  752.      */
  753.     bf = 0;
  754.  
  755.     for (t = 1; t <= 35; t++) {
  756.     if (t != 18)
  757.         bf += bam[BAM_BIT_MAP + 4 * (t - 1)];
  758.     }
  759.  
  760.     *l++ = 0;
  761.     *l++ = 0;
  762.     SET_LO_HI(l, bf);
  763.     memcpy(l, "BLOCKS FREE.", 12);
  764.     l += 12;
  765.     *l++ = (char) 0;
  766.  
  767.     addr += l - outputptr;
  768.  
  769.     outputptr[0] = addr & 0xff;
  770.     outputptr[1] = (addr / 256) & 0xff;
  771.  
  772.     /*
  773.      * end
  774.      */
  775.     *l++ = (char) 0;
  776.     *l++ = (char) 0;
  777.     *l++ = (char) 0;
  778.  
  779.     return l - origptr;
  780. }
  781.  
  782.  
  783.  
  784. /*
  785.  * Initialize slot find
  786.  */
  787. static void set_find_first_slot(char *name, int length, int type)
  788. {
  789.     floppy_find_name = name;
  790.     floppy_find_length = length;
  791.     floppy_find_type = type;
  792.  
  793.     /*
  794.      * Make sure find_next_slot() loads first directoryblock ...
  795.      */
  796.     floppy_find_slot = 8;
  797.     floppy_read_block(floppy_find_buffer, 18, 0);
  798. }
  799.  
  800. static byte *find_next_slot(void)
  801. {
  802.     static byte return_slot[32];
  803.     int     status;
  804.  
  805.     floppy_find_slot++;
  806.  
  807.     /*
  808.      * Loop all directoryblocks staring from track 18, sector 1
  809.      */
  810.     do {
  811.     /*
  812.      * Load next(first) directory block ?
  813.      */
  814.     if (floppy_find_slot >= 8) {
  815.         if (!(*floppy_find_buffer))
  816.         return NULL;
  817.  
  818.         floppy_find_slot = 0;
  819.  
  820.         floppy_find_current_track = (int) floppy_find_buffer[0];
  821.         floppy_find_current_sector = (int) floppy_find_buffer[1];
  822.  
  823.         status = floppy_read_block(floppy_find_buffer,
  824.         floppy_find_current_track,
  825.         floppy_find_current_sector);
  826.     }
  827.     while (floppy_find_slot < 8) {
  828.         if (floppy_name_match(&floppy_find_buffer[floppy_find_slot * 32],
  829.             floppy_find_name, floppy_find_length,
  830.             floppy_find_type)) {
  831.         memcpy(return_slot,
  832.             &floppy_find_buffer[floppy_find_slot * 32], 32);
  833.         return return_slot;
  834.         }
  835.         floppy_find_slot++;
  836.     }
  837.     } while (*floppy_find_buffer);
  838.  
  839.     /*
  840.      * If length < 0, create new directory-entry if possible
  841.      */
  842.     if (floppy_find_length < 0) {
  843.     int     s;
  844.  
  845.     for (s = 1; s < sector_map[18]; s++) {
  846.         if (allocate_sector(18, s)) {
  847.         floppy_find_buffer[0] = 18;
  848.         floppy_find_buffer[1] = s;
  849.         floppy_write_block(floppy_find_buffer,
  850.             floppy_find_current_track,
  851.             floppy_find_current_sector);
  852.         floppy_find_slot = 0;
  853.         memset(floppy_find_buffer, 0, 256);
  854.         floppy_find_buffer[1] = 0xff;
  855.         floppy_find_current_sector = s;
  856.         return floppy_find_buffer;
  857.         }
  858.     }
  859.  
  860.     }
  861.     return NULL;
  862. }
  863.  
  864.  
  865. static void no_a0_pads(unsigned char *ptr, int l)
  866. {
  867.     while (l--) {
  868.     if (*ptr == 0xa0)
  869.         *ptr = 0x20;
  870.  
  871.     ptr++;
  872.     }
  873. }
  874.  
  875.  
  876.  
  877. /*
  878.  * Read one block
  879.  */
  880. static int floppy_read_block(unsigned char *buf, int track, int sector)
  881. {
  882.     long offset, len;
  883.  
  884.     offset=offset_from_track_and_sector(track, sector);
  885.     if (offset<0) return -1;
  886.  
  887.     SetFPos(FloppyActiveFd, fsFromStart, offset);
  888.     len=256;
  889.     FSRead(FloppyActiveFd, &len, buf);
  890.     if (len<256) FloppyAlert("\pFloppy read error");
  891.     return 0;
  892. }
  893.  
  894.  
  895.  
  896. /*
  897.  * Write one block
  898.  */
  899. static int floppy_write_block(unsigned char *buf, int track, int sector)
  900. {
  901.     long offset, len;
  902.  
  903.     offset=offset_from_track_and_sector(track, sector);
  904.     if (offset<0) return -1;
  905.  
  906.     SetFPos(FloppyActiveFd, fsFromStart, offset);
  907.     len=256;
  908.     FSWrite(FloppyActiveFd, &len, buf);
  909.     if (len<256) FloppyAlert("\pFloppy write error");
  910.     return 0;
  911. }
  912.  
  913.  
  914. /*
  915.  * Error messages
  916.  */
  917. typedef struct errortext_s {
  918.     int     nr;
  919.     char   *text;
  920. }       errortext_t;
  921.  
  922. static errortext_t floppy_error_messages[] =
  923. {
  924.     {0, "OK"},
  925.     {1, "FILES SCRATCHED"},
  926.     {30, "SYNTAX ERROR"},
  927.     {60, "WRITE FILE OPEN"},
  928.     {61, "FILE NOT OPEN"},
  929.     {62, "FILE NOT FOUND"},
  930.     {63, "FILE EXISTS"},
  931.     {64, "FILE TYPE MISMATCH"},
  932.     {70, "NO CHANNEL"},
  933.     {72, "DISK FULL"},
  934.     {73, "TVR 1541 EMULATOR V1.0"},
  935.     {-1, 0},
  936. };
  937.  
  938.  
  939. /*
  940.  * Should set values to somewhere so that they could be read from
  941.  * command channel
  942.  */
  943. static void floppy_error(int code, int track, int sector)
  944. {
  945.     char   *message;
  946.     bufferinfo_t *p = &floppy_buffers[15];
  947.  
  948.     errortext_t *e = &floppy_error_messages[0];
  949.  
  950.     while (e -> nr >= 0 && e -> nr != code)
  951.     e++;
  952.  
  953.     if (e -> nr >= 0)
  954.     message = e -> text;
  955.     else
  956.     message = "UNKNOWN ERROR NUMBER";
  957.  
  958.     sprintf((char *)p -> buffer, "%02d, %s,%d,%d", code, message, track, sector);
  959.     p -> length = strlen((char *)p -> buffer);
  960.     p -> bufptr = 0;
  961. }
  962.  
  963.  
  964. static void remove_slot(unsigned char *slot)
  965. {
  966.     byte    buf[256];
  967.     int     tmp;
  968.     int     t, s;
  969.  
  970.     /*
  971.      * Find slot
  972.      */
  973.     for (tmp = 0; (tmp < 16) && slot[SLOT_NAME_OFFSET + tmp] != 0xa0; tmp++);
  974.  
  975.     set_find_first_slot((char *)&slot[SLOT_NAME_OFFSET], tmp,
  976.     slot[SLOT_TYPE_OFFSET] & 0x07);
  977.  
  978.     /*
  979.      * If slot slot found, remove
  980.      */
  981.     if (find_next_slot()) {
  982.     /*
  983.      * Free all buffers from bam
  984.      */
  985.     t = (int) floppy_find_buffer[floppy_find_slot * 32 + SLOT_FIRST_TRACK];
  986.     s = (int) floppy_find_buffer[floppy_find_slot * 32 + SLOT_FIRST_SECTOR];
  987.  
  988.     while (t) {
  989.         free_sector(t, s);
  990.         floppy_read_block(buf, t, s);
  991.         t = (int) buf[0];
  992.         s = (int) buf[1];
  993.     }
  994.  
  995.     /*
  996.      * Update bam
  997.      */
  998.     floppy_write_block(bam, 18, 0);
  999.  
  1000.     /*
  1001.      * Update directory entry
  1002.      */
  1003.     floppy_find_buffer[floppy_find_slot * 32 + SLOT_TYPE_OFFSET] = 0;
  1004.     floppy_write_block(floppy_find_buffer,
  1005.         floppy_find_current_track,
  1006.         floppy_find_current_sector);
  1007.     }
  1008. }
  1009.  
  1010.  
  1011.  
  1012. static int write_sequential_buffer(unsigned char *slot, unsigned char *buf, int length)
  1013. {
  1014.     static int t = 0, s;
  1015.     int     t_new, s_new;
  1016.     int     e;
  1017.  
  1018.     /*
  1019.      * First block of a file ?
  1020.      */
  1021.     if (t == 0) {
  1022.     e = alloc_free_sector(&t, &s);
  1023.     if (e < 0) {
  1024.         floppy_error(72, 0, 0);
  1025.         return -1;
  1026.     }
  1027.     slot[SLOT_FIRST_TRACK] = t;
  1028.     slot[SLOT_FIRST_SECTOR] = s;
  1029.     }
  1030.     if (length == WRITE_BLOCK) {
  1031.     /*
  1032.      * Write current sector and allocate next
  1033.      */
  1034.     e = alloc_free_sector(&t_new, &s_new);
  1035.     if (e < 0) {
  1036.         floppy_error(72, 0, 0);
  1037.         return -1;
  1038.     }
  1039.     buf[0] = t_new;
  1040.     buf[1] = s_new;
  1041.  
  1042.     floppy_write_block(buf, t, s);
  1043.  
  1044.     t = t_new;
  1045.     s = s_new;
  1046.  
  1047.     if (!(++slot[SLOT_NR_BLOCKS]))
  1048.         ++slot[SLOT_NR_BLOCKS + 1];
  1049.  
  1050.     } else {
  1051.     /*
  1052.      * Write last block
  1053.      */
  1054.     buf[0] = 0;
  1055.     buf[1] = length - 1;
  1056.  
  1057.     floppy_write_block(buf, t, s);
  1058.  
  1059.     t = 0;
  1060.  
  1061.     if (!(++slot[SLOT_NR_BLOCKS]))
  1062.         ++slot[SLOT_NR_BLOCKS + 1];
  1063.     }
  1064.     return 0;
  1065. }
  1066.  
  1067.  
  1068.  
  1069. static int alloc_free_sector(int *track, int *sector)
  1070. {
  1071.     int     t, s;
  1072.  
  1073.     for (t = 17; t >= 1; t--) {
  1074.     for (s = 0; s < sector_map[t]; s++) {
  1075.         if (allocate_sector(t, s)) {
  1076.         *track = t;
  1077.         *sector = s;
  1078.         return 0;
  1079.         }
  1080.     }
  1081.     }
  1082.  
  1083.     for (t = 19; t <= 35; t++) {
  1084.     for (s = 0; s < sector_map[t]; s++) {
  1085.         if (allocate_sector(t, s)) {
  1086.         *track = t;
  1087.         *sector = s;
  1088.         return 0;
  1089.         }
  1090.     }
  1091.     }
  1092.     return -1;
  1093. }
  1094.  
  1095.  
  1096. static int allocate_sector(int track, int sector)
  1097. {
  1098.     /*
  1099.      * Macros use this
  1100.      */
  1101.     byte   *bamp;
  1102.  
  1103.     bamp = &bam[BAM_BIT_MAP + 4 * (track - 1)];
  1104.  
  1105.     if (BAM_ISSET(sector)) {
  1106.     (*bamp)--;
  1107.     BAM_CLR(sector);
  1108.  
  1109.     return 1;
  1110.     }
  1111.     return 0;
  1112. }
  1113.  
  1114.  
  1115. /*
  1116.  * Return block offset on 'disk file' according to track and sector
  1117.  */
  1118. static off_t offset_from_track_and_sector(int track, int sector)
  1119. {
  1120.     int     sectors, i;
  1121.  
  1122.     if ((track < 1) || (track > 35))
  1123.     return (-1);
  1124.  
  1125.     for (sectors = 0, i = 1; i < track; i++) {
  1126.     sectors += sector_map[i];
  1127.     }
  1128.  
  1129.     if ((sector < 0) || (sector >= sector_map[track]))
  1130.     return (-1);
  1131.  
  1132.     sectors += sector;
  1133.  
  1134.     return 256L * sectors;
  1135. }
  1136.  
  1137.  
  1138.  
  1139. static int free_sector(int track, int sector)
  1140. {
  1141.     byte   *bamp;
  1142.  
  1143.     bamp = &bam[BAM_BIT_MAP + 4 * (track - 1)];
  1144.  
  1145.     if (!(BAM_ISSET(sector))) {
  1146.     BAM_SET(sector);
  1147.     (*bamp)++;
  1148.     return 1;
  1149.     }
  1150.     return 0;
  1151. }
  1152.  
  1153.  
  1154. /*
  1155.  * If type is 0, match for next slot with same name
  1156.  * If type is nonzero, match next that has the same id and name
  1157.  */
  1158. static int floppy_name_match(unsigned char *slot, char *name, int length, int type)
  1159. {
  1160.     int     i;
  1161.     /* int comma = 0; */
  1162.  
  1163.     if (length < 0) {
  1164.     if (slot[SLOT_TYPE_OFFSET])
  1165.         return 0;
  1166.     else
  1167.         return 1;
  1168.     }
  1169.     if (!slot[SLOT_TYPE_OFFSET])
  1170.     return 0;
  1171.  
  1172.     if (length >= 16)
  1173.     length = 16;
  1174.  
  1175.     for (i = 0; i < length; i++) {
  1176.     switch (name[i]) {
  1177.       case '?':
  1178.         /*
  1179.          * Match any character
  1180.          */
  1181.         break;
  1182.  
  1183.       case '*':
  1184.         /*
  1185.          * Make a match
  1186.          */
  1187.         i = 16;
  1188.         break;
  1189.  
  1190.       default:
  1191.         if ((byte)name[i] != slot[i + SLOT_NAME_OFFSET])
  1192.         return 0;
  1193.     }
  1194.     }
  1195.  
  1196.     /*
  1197.      * Got name match ?
  1198.      */
  1199.     if (i < 16 && slot[SLOT_NAME_OFFSET + i] != 0xa0)
  1200.     return 0;
  1201.  
  1202.     if (type && type != (slot[SLOT_TYPE_OFFSET] & 0x07))
  1203.     return 0;
  1204.  
  1205.     return 1;
  1206. }
  1207.  
  1208.  
  1209.  
  1210. /*
  1211.  * Close all channels. This happens on 'I' -command and on command-
  1212.  * channel close
  1213.  */
  1214. void floppy_close_all_channels(void)
  1215. {
  1216.     int     i;
  1217.     bufferinfo_t *p;
  1218.  
  1219.     for (i = 0; i <= 15; i++) {
  1220.     p = &floppy_buffers[i];
  1221.  
  1222.     if (p -> mode != BUFFER_NOT_IN_USE && p -> mode != BUFFER_COMMAND_CHANNEL)
  1223.         Close1541(i);
  1224.     }
  1225. }
  1226.  
  1227.  
  1228. static int do_initialize(void)
  1229. {
  1230.  
  1231.     floppy_close_all_channels();
  1232.     return kSerialOK;
  1233. }
  1234.  
  1235. static int do_validate(void)
  1236. {
  1237.     int     t, s;
  1238.     byte *b;
  1239.     byte    tmp[256];
  1240.  
  1241.     do_initialize();
  1242.  
  1243.     b = (byte *) bam + BAM_BIT_MAP;
  1244.  
  1245.     for (t = 1; t <= 35; t++) {
  1246.     *b++ = 0;
  1247.     *b++ = 0;
  1248.     *b++ = 0;
  1249.     *b++ = 0;
  1250.  
  1251.     for (s = 0; s < sector_map[t]; s++)
  1252.         free_sector(t, s);
  1253.     }
  1254.  
  1255.     set_find_first_slot("*", 1, 0);
  1256. /*
  1257.     First map out the directory itself.    -Dan Miner
  1258.     And another one bites the dust....  :)
  1259. */
  1260.     t = 18; s = 0;
  1261.     while(t) {
  1262.         allocate_sector(t, s);
  1263.         floppy_read_block(tmp, t, s);
  1264.         t = (int) tmp[0];
  1265.         s = (int) tmp[1];
  1266.     }
  1267.  
  1268.     while ((b = (byte *) find_next_slot())) {
  1269.     if (b[SLOT_TYPE_OFFSET]) {
  1270.         floppy_find_buffer[floppy_find_slot * 32 + SLOT_TYPE_OFFSET] |= 0x80;
  1271.         floppy_write_block(floppy_find_buffer, floppy_find_current_track,
  1272.         floppy_find_current_sector);
  1273.         t = (int) b[SLOT_FIRST_TRACK];
  1274.         s = (int) b[SLOT_FIRST_SECTOR];
  1275.  
  1276.         while (t) {
  1277.         allocate_sector(t, s);
  1278.         floppy_read_block(tmp, t, s);
  1279.         t = (int) tmp[0];
  1280.         s = (int) tmp[1];
  1281.         }
  1282.     }
  1283.     }
  1284.  
  1285.     floppy_write_block(bam, 18, 0);
  1286.     return kSerialOK;
  1287. }
  1288.  
  1289.  
  1290. static int do_format(char *name, unsigned char *id, unsigned char *minus)
  1291. {
  1292.     byte    tmp[256];
  1293.     int     status;
  1294.  
  1295.     byte    null = 0;
  1296.  
  1297.     if (!name) {
  1298.     floppy_error(30, 0, 0);
  1299.     return kFloppyError;
  1300.     }
  1301.     /*
  1302.      * If id, skip comma
  1303.      */
  1304.     if (id)
  1305.     *id++ = 0;
  1306.     else
  1307.     id = &null;
  1308.  
  1309.     /*
  1310.      * Make dir-entry
  1311.      */
  1312.     memset(tmp, 0, 256);
  1313.     tmp[1] = 255;
  1314.     floppy_write_block(tmp, 18, 1);
  1315.  
  1316.     /*
  1317.      * Make bam
  1318.      */
  1319.     memset(bam, 0, 256);
  1320.     bam[0] = 18;
  1321.     bam[1] = 1;
  1322.     bam[2] = 65;
  1323.     memset(bam + BAM_DISK_NAME, 0xa0, 16);
  1324.     mystrncpy(bam + BAM_DISK_NAME, (byte *)name + 1, 16);
  1325.  
  1326.     memset(bam + BAM_DISK_ID, 0xa0, 5);
  1327.     mystrncpy(bam + BAM_DISK_ID, id, 2);
  1328.     bam[BAM_VERSION] = 50;
  1329.     bam[BAM_VERSION + 1] = 65;
  1330.     status = do_validate();
  1331.     allocate_sector(18, 1);        /* first directory block-  Dan Miner */
  1332.     floppy_write_block(bam, 18, 0);
  1333.     return status;
  1334. }
  1335.  
  1336.  
  1337. static int do_command_channel_write(unsigned char *buf, int length)
  1338. {
  1339.     int     status = kFloppyError;
  1340.     static byte p[256];
  1341.     char   *name;
  1342.     byte   *minus;
  1343.     byte   *id;
  1344.  
  1345.     memcpy(p, buf, length);
  1346.     p[length] = 0;
  1347.  
  1348.     name = (char *)memchr(p, ':', length);
  1349.     id = (byte *)memchr(p, ',', length);
  1350.     minus = (byte *)memchr(p, '-', length);
  1351.  
  1352.     floppy_error(0, 0, 0);
  1353.  
  1354.     switch (p[0]) {
  1355.       case 'N':
  1356.     status = do_format(name, id, minus);
  1357.     break;
  1358.       case 'C':
  1359.     break;
  1360.  
  1361.       case 'R':
  1362.     break;
  1363.  
  1364.       case 'S':
  1365.     break;
  1366.  
  1367.       case 'I':
  1368.     status = do_initialize();
  1369.     break;
  1370.  
  1371.       case 'V':
  1372.     status = do_validate();
  1373.     break;
  1374.  
  1375.       case 'B':
  1376.     if (!minus || !name)
  1377.         floppy_error(30, 0, 0);
  1378.     else
  1379.         status = do_block_command(minus[1], name + 1);
  1380.     break;
  1381.  
  1382.       case 'U':
  1383.     switch (p[1]) {
  1384.       case '1':
  1385.       case 'A':
  1386.         if (name)
  1387.         status = do_block_command('R', name + 1);
  1388.         break;
  1389.  
  1390.       case '2':
  1391.       case 'B':
  1392.         if (name)
  1393.         status = do_block_command('W', name + 1);
  1394.         break;
  1395.     }
  1396.     break;
  1397.  
  1398.     }
  1399.  
  1400.     return status;
  1401. }
  1402.  
  1403.  
  1404.  
  1405. static int do_block_command(char command, char *buffer)
  1406. {
  1407.     int     l;
  1408.  
  1409.     int     channel = 0;
  1410.     int     drive = 0;
  1411.     int     track = 0;
  1412.     int     sector = 0;
  1413.     int     position = 0;
  1414.  
  1415.     switch (command) {
  1416.       case 'R':
  1417.       case 'W':
  1418.     l = sscanf(buffer, "%d %d %d %d", &channel, &drive,
  1419.         &track, §or);
  1420.     if (l < 4) {
  1421.         l = sscanf(buffer, "%d,%d,%d,%d", &channel, &drive,
  1422.         &track, §or);
  1423.         if (l < 4) {
  1424.         floppy_error(30, 0, 0);
  1425.         return kFloppyError;
  1426.         }
  1427.     }
  1428.     if (floppy_buffers[channel].mode != BUFFER_MEMORY_BUFFER) {
  1429.         floppy_error(30, 0, 0);
  1430.         return kFloppyError;
  1431.     }
  1432.     if (command == 'W')
  1433.         floppy_write_block(floppy_buffers[channel].buffer,
  1434.         track, sector);
  1435.     else
  1436.         floppy_read_block(floppy_buffers[channel].buffer,
  1437.         track, sector);
  1438.  
  1439.     floppy_buffers[channel].bufptr = 0;
  1440.     break;
  1441.  
  1442.       case 'A':
  1443.       case 'F':
  1444.     l = sscanf(buffer, "%d %d %d", &drive, &track, §or);
  1445.  
  1446.     if (l < 3) {
  1447.         l = sscanf(buffer, "%d,%d,%d", &drive, &track, §or);
  1448.  
  1449.         if (l < 3) {
  1450.         floppy_error(30, 0, 0);
  1451.         return kFloppyError;
  1452.         }
  1453.     }
  1454.     if (command == 'A')
  1455.         allocate_sector(track, sector);
  1456.     else
  1457.         free_sector(track, sector);
  1458.     break;
  1459.  
  1460.       case 'P':
  1461.     l = sscanf(buffer, "%d %d", &channel, &position);
  1462.  
  1463.     if (l < 2) {
  1464.         l = sscanf(buffer, "%d,%d", &channel, &position);
  1465.  
  1466.         if (l < 2) {
  1467.         floppy_error(30, 0, 0);
  1468.         return kFloppyError;
  1469.         }
  1470.     }
  1471.     floppy_buffers[channel].bufptr = position;
  1472.     break;
  1473.  
  1474.       default:
  1475.     floppy_error(30, 0, 0);
  1476.     return kFloppyError;
  1477.     }
  1478.     return kSerialOK;
  1479. }
  1480.  
  1481.  
  1482.  
  1483. void AttachFloppyImage(FSSpec *spec)
  1484. {
  1485.     floppy_close_all_channels();
  1486.  
  1487.     if (floppyInDrive) FSClose(FloppyActiveFd);
  1488.     floppyInDrive=0;
  1489.  
  1490.     if (spec==NULL)
  1491.     {
  1492.         floppyInDrive=0;
  1493.         return;
  1494.     }
  1495.  
  1496.     if (FSpOpenDF(spec, fsRdWrPerm, &FloppyActiveFd)!=noErr)
  1497.     {
  1498.         floppyInDrive=0;
  1499.         return;
  1500.     }
  1501.  
  1502.     floppyInDrive=1;
  1503.     floppy_read_block(bam, 18, 0);
  1504. }
  1505.  
  1506. static int mystrncpy(unsigned char *d, unsigned char *s, int n)
  1507. {
  1508.     while (n-- && *s)
  1509.     *d++=*s++;
  1510.     return (n);
  1511. }
  1512.  
  1513. void CreateImage(FSSpec *spec)
  1514. {
  1515.     byte block[256];
  1516.     int    i;
  1517.     long len;
  1518.     short fnum;
  1519.     
  1520.     for (i=0; i<256; i++) block[i]=0;
  1521.  
  1522.     FSpCreate(spec, (OSType)APPLTYPE, (OSType)DISKFTYPE, 0);
  1523.     FSpOpenDF(spec, fsRdWrPerm, &fnum);
  1524.     
  1525.     len=256;
  1526.     for (i=0; i < 683; i++) FSWrite(fnum, &len, block);
  1527.     FSClose(fnum);
  1528. }
  1529.  
  1530.  
  1531. void FloppyCreateImage(void)
  1532. {
  1533.     StandardFileReply reply;
  1534.     static char *initString="N0:MAC64 FLOPPY,00";
  1535.     
  1536.     StandardPutFile("\pCreate New Image:", "\pDISK.D64", &reply);
  1537.     
  1538.     if (reply.sfGood)
  1539.     {
  1540.         SetCursor(&diskCursor);
  1541.         
  1542.         CreateImage(&reply.sfFile);
  1543.         AttachFloppyImage(&reply.sfFile);
  1544.         do_command_channel_write((byte *)initString, strlen(initString));
  1545.  
  1546.         if (programMode==kRunning) SetCursor(&commieCursor);
  1547.         else SetCursor(&qd.arrow);
  1548.     }
  1549.     
  1550.     if (programMode==kRunning) SetCursor(&commieCursor);
  1551.     else SetCursor(&qd.arrow);
  1552. }
  1553.  
  1554. void FloppySelectImage(void)
  1555. {
  1556.     StandardFileReply reply;
  1557.     
  1558.     StandardGetFile(nil, (short)-1, nil, &reply);
  1559.     if (reply.sfGood)
  1560.     {
  1561.         AttachFloppyImage(&reply.sfFile);
  1562.         do_initialize();
  1563.     }
  1564.     
  1565.     if (programMode==kRunning) SetCursor(&commieCursor);
  1566.     else SetCursor(&qd.arrow);
  1567. }
  1568.  
  1569. void FloppyCopyTo(void)
  1570. {
  1571.     StandardFileReply reply;
  1572.     short fNum;
  1573.     long size;
  1574.     byte data;
  1575.     
  1576.     if (floppyInDrive==0)
  1577.     {
  1578.         FloppyAlert("\pNo Floppy Image");
  1579.         return;
  1580.     }
  1581.         
  1582.     StandardGetFile(nil, (short)-1, nil, &reply);
  1583.     if (reply.sfGood)
  1584.     {
  1585.         SetCursor(&diskCursor);
  1586.  
  1587.         FSpOpenDF(&reply.sfFile, fsRdPerm, &fNum);
  1588.         PetConvString(reply.sfFile.name);
  1589.         Open1541((char *)(&reply.sfFile.name[1]), (int)reply.sfFile.name[0], 1);
  1590.         size=1;
  1591.         while (size)
  1592.         {
  1593.             FSRead(fNum, &size, &data);
  1594.             if (size) Write1541(data, 1);
  1595.         }
  1596.         FSClose(fNum);
  1597.         Close1541(1);
  1598.     }
  1599.     
  1600.     if (programMode==kRunning) SetCursor(&commieCursor);
  1601.     else SetCursor(&qd.arrow);
  1602. }
  1603.  
  1604. int ExternalRead(unsigned char *buf, int track, int sector)
  1605. {
  1606.     return floppy_read_block(buf, track, sector);
  1607. }
  1608.